﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using SimpleTaskManager.Domain.Abstract;
using SimpleTaskManager.Domain.Entities;

namespace SimpleTaskManager.Domain.Concrete
{
    /// <summary>
    /// A repository containing the tasks and methods to manage them
    /// </summary>
    public class EFTaskRepository : ITaskRepository
    {
        private EFDbContext context = new EFDbContext();

        /// <summary>
        /// Gets the collection of the tasks present in the application
        /// </summary>
        public IQueryable<Task> Tasks
        {
            get { return context.Tasks; }
        }

        /// <summary>
        /// Adds a sub task to a task.
        /// </summary>
        /// <param name="id">The ID of the parent task</param>
        /// <param name="task">The new task entity, which will be added as subtask</param>
        public void CreateSubTask(int id, Task task)
        {
            task.StartDate = DateTime.Now;
            task.Rating = 0;
            task.Status = TaskStatusEnum.New;
            if (id >= 1)
            {
                var parentTask = context.Tasks.Single(t => t.TaskID.Equals(id));
                parentTask.SubTasks.Add(task);
            }
            else
            {
                context.Projects.Add(new Project { MainTask = task });
            }

            context.SaveChanges();
        }

        /// <summary>
        /// Saves the modifications of a task.
        /// </summary>
        /// <param name="task">The task to modify</param>
        public void EditTask(Task task)
        {
            context.Entry(task).State = EntityState.Modified;
            context.SaveChanges();
        }

        /// <summary>
        /// Deletes a task.
        /// </summary>
        /// <param name="id">The ID of the task to delete</param>
        public void DeleteTask(int id)
        {
            Task task = context.Tasks.Single(t => t.TaskID == id);

            //Delete the sub tasks
            while (task.SubTasks.Count > 0)
                DeleteTask(task.SubTasks.First().TaskID);

            //Delete the task
            context.Tasks.Remove(task);
            context.SaveChanges();
        }

        /// <summary>
        /// Adds a report to a task.
        /// </summary>
        /// <param name="taskId">The ID of the task to which the report will be added</param>
        /// <param name="report">The new report entity that will be added to the task</param>
        public void AddReport(int taskId, ReportHeader report)
        {
            //Get the task instance
            Task task = context.Tasks.Single(t => t.TaskID == taskId);
            //Add the report to the task
            task.Reports.Add(report);

            context.SaveChanges();
        }

        /// <summary>
        /// Sets a specified report to approved.
        /// </summary>
        /// <param name="taskId">The ID of the task which contains the report</param>
        /// <param name="reportId">The ID of the report which will be approved</param>
        /// <param name="approverId">The ID of the user who approved the report</param>
        public void ApproveReport(int taskId, int reportId, int approverId)
        {
            //Get the task instance
            Task task = context.Tasks.Single(t => t.TaskID == taskId);
            //Set the approver
            task.Reports.Single(r => r.ReportHeaderID.Equals(reportId)).ApprovedById = approverId;

            context.SaveChanges();
        }

        /// <summary>
        /// Adds a user to the group associated with the a task.
        /// </summary>
        /// <param name="taskId">The ID of the task which group will be extended</param>
        /// <param name="userId">The ID of the user who will be added to the group</param>
        public void AssignUserToTask(int taskId, int userId)
        {
            //Get the task instance
            Task task = context.Tasks.Single(t => t.TaskID == taskId);
            //Get the user and add him to the group
            task.Group.Add(context.Users.Single(u => u.UserID == userId));

            context.SaveChanges();
        }

        /// <summary>
        /// Removes a user from the group of the task.
        /// </summary>
        /// <param name="taskId">The ID of the task which group will be changed</param>
        /// <param name="userId">The ID of the user who will be deleted from the group</param>
        public void RemoveUserFromGroup(int taskId, int userId)
        {
            //Get the task instance
            Task task = context.Tasks.Single(t => t.TaskID == taskId);
            //Get the user and remove him from the group
            task.Group.Remove(context.Users.Single(u => u.UserID == userId));

            context.SaveChanges();
        }

        /// <summary>
        /// Adds a task as required to another task.
        /// </summary>
        /// <param name="taskId">The ID of the task which will require the other task</param>
        /// <param name="reqId">The ID of the required task</param>
        public void AddRequirement(int taskId, int reqId)
        {
            //Get the task instance
            Task task = context.Tasks.Single(t => t.TaskID == taskId);
            //Get the required task and add it to the requirements
            task.Requirements.Add(context.Tasks.Single(t => t.TaskID == reqId));

            context.SaveChanges();
        }

        /// <summary>
        /// Removes a task from the requirements of another task
        /// </summary>
        /// <param name="taskId">The ID of the task which won't require the other task any more</param>
        /// <param name="reqId">The ID of the task which will be removed from the requirements</param>
        public void RemoveRequirement(int taskId, int reqId)
        {
            //Get the task instance
            Task task = context.Tasks.Single(t => t.TaskID == taskId);
            //Get the required task and remove it from the requirements
            task.Requirements.Remove(context.Tasks.Single(t => t.TaskID == reqId));

            context.SaveChanges();
        }
    }
}
